package shiqi.service.superman;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import shiqi.entity.Superman;
import shiqi.mapper.SupermanMapper;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @author shiqi
 * @version 1.0.0
 * @ClassName SupermanService.java
 * @Description
 * @createTime 2022-05-06
 */
@Service
public class SupermanService {

    @Resource
    private SupermanMapper supermanMapper;

    /**
     * 查询所有赛亚人
     * @return
     */
    public List<Superman> getAllSuperman() {
        // 查出所有的根节点：孙悟空、贝吉塔
        List<Superman> rootSupermanList = getRootSuperman();
        // 分别查出孙悟空和贝吉塔的孩子，并设置
        for (Superman superman : rootSupermanList) {
            List<Superman> children = queryChildrenByParent(superman);
            superman.setChildren(children);
        }
        // 返回
        return rootSupermanList;
    }

    /**
     * 查出根节点（pid=0）
     * @return
     */
    private List<Superman> getRootSuperman() {
        QueryWrapper<Superman> supermanQueryWrapper = new QueryWrapper<>();
        supermanQueryWrapper.eq("pid", 0);
        return supermanMapper.selectList(supermanQueryWrapper);
    }

    /**
     * 递归查询孩子
     * 优点：直观（并没有觉得...递归对我而言很难）
     * 缺点：在我们程序中，每次递归调用都会查询一次数据库，效率非常低
     * @param parent
     * @return
     */
    private List<Superman> queryChildrenByParent(Superman parent) {
        // 准备查询条件query
        QueryWrapper<Superman> supermanQueryWrapper = new QueryWrapper<>();
        supermanQueryWrapper.eq("pid", parent.getId());
        // 查出孩子
        List<Superman> children = supermanMapper.selectList(supermanQueryWrapper);
        // 查出每个孩子的孩子，并设置
        for (Superman child : children) {
            List<Superman> grandChildren = queryChildrenByParent(child);// 递归
            child.setChildren(grandChildren);
        }
        return children;
    }


    /**
     * 查询所有赛亚人(只访问一次数据库）
     * 优点：只查询一次数据库，而且很直观（个人觉得比递归直观)
     * 缺点：双层for效率仍然很低，如果list长度为n，那么要循环n2次。也就是说，如果现在这个List表示的是全国的高校（学校-院系-专业），截止至2019年6月15日，教育部公布的全国高等学校共计有2956所，那么需要循环29562次，差不多是30002=900w次...
     * @return
     */
    public List<Superman> getAllSuperman1() {
        QueryWrapper<Superman> supermanQueryWrapper = new QueryWrapper<>();
        supermanQueryWrapper.eq("1", "1");
        // 先查出全部数据
        List<Superman> data = supermanMapper.selectList(supermanQueryWrapper);
        // 用来存储最终的结果
        List<Superman> list = new ArrayList<>();

        // 双层for循环完成数据组装
        for (Superman left : data) {
            for (Superman right : data) {
                // 如果右边是左边的孩子，就设置进去
                if(left.getId().equals(right.getPid())){
                    left.getChildren().add(right);
                }
            }
            // 只把第1级加到list
            if(left.getPid() == 0){
                list.add(left);
            }
        }

        return list;
    }


    /**
     * 查询所有赛亚人（map集合读取）
     * 优点：查询效率提高了
     * 缺点：空间利用率降低了（List/Array可以只存元素，而Map需要额外存储key）
     * @return
     */
    public List<Superman> getAllSuperman2() {
        // 用来存储最终的结果
        List<Superman> list = new ArrayList<>();

        QueryWrapper<Superman> supermanQueryWrapper = new QueryWrapper<>();
        supermanQueryWrapper.eq("1", "1");
        // 先查出全部数据
        List<Superman> data = supermanMapper.selectList(supermanQueryWrapper);
        // Map，用来转存List
        HashMap<Integer, Superman> hashMap = new HashMap<>();

        // 先把List转为Map，把Map作为左侧parent
        for (Superman superman : data) {
            hashMap.put(superman.getId(), superman);
        }

        // 右边child进行for循环找parent
        for (Superman child : data) {
            if(child.getPid() == 0){
                list.add(child);// 找到第一级（悟空、贝吉塔）
            } else {
                // 不是第一级，那么肯定有parent，帮它找到parent，并把它自己设置到parent里
                Superman parent = hashMap.get(child.getPid());// hash索引！找爸爸很快！
                parent.getChildren().add(child);
            }
        }

        return list;
    }
}

